<?php

require('db.php');

class generator {
    private $db_meta;
    private $db_data;
    private $singles;
    private $patterns;
    private $elements;
    private $values;
    private $items;
    private $queries;
    private $attributes;
    private $styles;
    private $rule;
    
    public function __construct($config_meta, $config_data, $rule) {
        $this->singles = ',img,br,hr,input,';
        $this->patterns = ',view,insert,';
        $this->db_meta = new db($config_meta);
        $this->db_data = new db($config_data);
        // get all elements
        $elements = $this->db_meta->query('
            select *
            from ta.elements
        ');
        $this->elements = array();
        foreach ($elements as $element) {
            $this->elements[$element['id']] = $element;
        }
        $elements = null;
        // get all values
        $values = $this->db_meta->query('
            select *
            from ta.values
        ');
        $this->values = array();
        foreach ($values as $value) {
            $this->values[$value['element']] = $value['value'];
        }
        $values = null;
        // get all items
        $items = $this->db_meta->query('
            select *
            from ta.items
            group by element,`index`
        ');
        $this->items = array();
        foreach ($items as $item) {
            if (!isset($this->items[$item['element']])) {
                $this->items[$item['element']] = array();
            }
            $this->items[$item['element']][] = $item['value'];
        }
        $items = null;
        // get all queries
        $queries = $this->db_meta->query('
            select *
            from ta.queries
        ');
        $this->queries = array();
        foreach ($queries as $query) {
            $this->queries[$query['element']] = $query['query'];
        }
        $queries = null;
        // get all attributes
        $attributes = $this->db_meta->query('
            select *
            from ta.attributes
        ');
        $this->attributes = array();
        foreach ($attributes as $attribute) {
            if (!isset($this->attributes[$attribute['element']])) {
                $this->attributes[$attribute['element']] = array();
            }
            $this->attributes[$attribute['element']][$attribute['name']] = $attribute['value'];
        }
        $attributes = null;
        // get all styles
        $styles = $this->db_meta->query('
            select *
            from ta.styles
        ');
        $this->styles = array();
        foreach ($styles as $style) {
            $this->styles[$style['selector']] = $style;
        }
        $styles = null;
        // get rule
        $this->rule = $rule;
    }
    
    public function is_single($type) { // cek apakah elemen bertipe single tag
        if (strpos($this->singles, ','.$type.',') === false) {
            return false;
        } else {
            return true;
        }
    }
    
    public function is_pattern($type) { // cek apakah elemen bertipe pattern
        if (strpos($this->patterns, ','.$type.',') === false) {
            return false;
        } else {
            return true;
        }
    }
    
    public function open_tag($id, $key = false) { // tulis tag pembuka
        $retval = '';
        if (!$this->is_pattern($this->elements[$id]['type'])) {
            $retval .= '<';
            $retval .= $this->elements[$id]['type'];
            $retval .= ' id="';
            $retval .= $id;
            if ($key !== false) {
                if ($key[0] == '-') {
                    $retval .= $key;
                } else {
                    $retval .= '-'.$key;
                }
            }
            $retval .= '"';
            if (isset($this->attributes[$id])) {
                foreach ($this->attributes[$id] as $name => $value) {
                    $retval .= ' '.$name.'="';
                    if (isset($this->rule[$id]) && isset($this->rule[$id]['attributes'][$name])) {
                        $retval .= $this->rule[$id]['attributes'][$name];
                    } else {
                        $retval .= $this->attributes[$id][$name];
                    }
                    $retval .= '"';
                }
            }
            $retval .= '>';
            if ($this->is_single($this->elements[$id]['type'])) {
                $retval .= "\n";
            }
        }
        return $retval;
    }
    
    public function close_tag($id) { // tulis tag penutup
        $retval = '';
        if (!$this->is_pattern($this->elements[$id]['type'])) {
            if (!$this->is_single($this->elements[$id]['type'])) {
                $retval .= '</'.$this->elements[$id]['type'].'>'."\n";
            }
        }
        return $retval;
    }
    
    public function generate_child($id, $index, $data) { // split child then generate them
        $retval = '';
        $children = explode(',', $this->elements[$id]['child']);
        foreach ($children as $child) {
            $retval .= $this->generate($child, $index, $data);
        }
        return $retval;
    }
    
    public function generate($id, $index = false, $data = false) {
        $retval = ''; // inisialisasi return value
        if (substr($id, -1) == '*') { // berarti pengulangan
            $id = substr($id, 0, -1);
            if (isset($this->elements[$id])) { // element yang dimaksud ada maka lanjutkan generate element ini
                if ($this->is_single($this->elements[$id]['type'])) { // berarti element ini single tag
                    if (isset($this->rule[$id]['items'])) { // berarti ada rule-nya
                        foreach ($this->rule[$id]['items'] as $key => $value) {
                            $retval .= $this->open_tag($id, $index.'-'.$key);
                        }
                    } elseif (isset($this->items[$id])) { // berarti items dari metadata
                        foreach ($this->items[$id] as $key => $value) {
                            $retval .= $this->open_tag($id, $index.'-'.$key);
                        }
                    }
                } else { // berarti elemen ini paired element
                    if (isset($this->rule[$id]['items'])) { // berarti isi element ini mengulang berdasarkan values dari rule
                        foreach ($this->rule[$id]['items'] as $key => $value) {
                            $retval .= $this->open_tag($id, $index.'-'.$key);
                            $retval .= $value;
                            $retval .= $this->generate_child($id, $key, $data);
                            $retval .= $this->close_tag($id);
                        }
                    } elseif (isset($this->items[$id])) { // berarti isi element ini mengulang berdasarkan values dari metadata
                        foreach ($this->items[$id] as $key => $value) {
                            $retval .= $this->open_tag($id, $index.'-'.$key);
                            $retval .= $value;
                            $retval .= $this->generate_child($id, $key, $data);
                            $retval .= $this->close_tag($id);
                        }
                    } elseif ($data !== false) { // berarti isi elemen ini column db_data
                        $key = 0;
                        foreach ($data as $value) {
                            $retval .= $this->open_tag($id, $index.'-'.$key);
                            $retval .= $value;
                            $retval .= $this->generate_child($id, $key, $data);
                            $retval .= $this->close_tag($id);
                            $key++;
                        }
                    } elseif (isset($this->rule[$id]['query'])) { // berarti isi element ini dengan mengambil data dari database
                        $db_data = $this->db_data->query($this->rule[$id]['query']);
                        foreach ($db_data as $key => $row) {
                            $retval .= $this->open_tag($id, $index.'-'.$key);
                            $retval .= $this->generate_child($id, $key, $row);
                            $retval .= $this->close_tag($id);
                        }
                    } elseif (isset($this->queries[$id])) { // berarti isi element ini dengan mengambil data dari database
                        $db_data = $this->db_data->query($this->queries[$id]);
                        foreach ($db_data as $key => $row) {
                            $retval .= $this->open_tag($id, $index.'-'.$key);
                            $retval .= $this->generate_child($id, $key, $row);
                            $retval .= $this->close_tag($id);
                        }
                    } else { // lainnya
                        $retval .= $this->generate($id, $index, $data);
                    }
                }
            }
        } elseif (isset($this->elements[$id])) { // element yang dimaksud ada maka lanjutkan generate element ini
            $retval .= $this->open_tag($id, $index);
            if ($this->is_single($this->elements[$id]['type'])) { // berarti element ini single tag
                // do nothing
            } else { // element yg dimaksud bukan single element
                if ($index !== false) { // berarti elemen ini anggota pengulangan
                    if (isset($this->rule[$id]['items'][$index])) {
                        $retval .= $this->rule[$id]['items'][$index];
                    } elseif (isset($this->items[$id][$index])) {
                        $retval .= $this->items[$id][$index];
                    } elseif ($data !== false) {
                        $retval .= $data[$index];
                    }
                } elseif (isset($this->rule[$id]['value'])) { // berarti isi element dengan dynamic value
                    $retval .= $this->rule[$id]['value'];
                } elseif (isset($this->values[$id])) { // berarti isi element dengan dynamic value
                    $retval .= $this->values[$id];
                }
                $retval .= $this->generate_child($id, $index, $data);
                $retval .= $this->close_tag($id);
            }
        }
        return $retval; // oke return
    }
    
    public function styling($rule) {
    }
}
